home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 4_0 / UNZIP102 / UNZIP.C < prev    next >
Text File  |  1990-07-14  |  44KB  |  1,932 lines

  1. /* -------------------------------------------------------------------------- */
  2. /* -------------------------------------------------------------------------- */
  3.  
  4. /*
  5.  *   UnZip - A ZIP file extract utility for ZIP files and ZIP ".EXE" files
  6.  *   archived using PKZIP 1.10 or earlier. Recognizes and dearchives ╥stored╙, 
  7.  *   ╥shrunk╙, ╥reduced╙ and ╥imploded╙ files.
  8.  *
  9.  *   VERSION: UnZip 1.02c ╤ July 14, 1990
  10.  *
  11.  *   Translated into Lightspeed C v.4.0 and adapted for the Mac by A.P. Maika,
  12.  *   (utilizing TransSkel 2.01 and TransDisplay 2.0 written by Paul DuBois)
  13.  *
  14.  *   Dearchiving code for ╥extracting╙, ╥unshrinking╙, and ╥expanding╙ written
  15.  *   in Turbo C v. 2.0 ⌐ Samuel H. Smith (version 1.2 of 03-15-89)
  16.  *   Adapted for the Atari ST and CRC inline assembly code ⌐ Darin Wayrynen
  17.  *        
  18.  *   Dearchiving code for ╥exploding╙ derived from Turbo Pascal v. 5.0
  19.  *   source ⌐ R.P. Byrne (version 2.0 of 07-31-89)
  20.  */
  21.  
  22. /* -------------------------------------------------------------------------- */
  23. /* -------------------------------------------------------------------------- */
  24. /*
  25.  *                     Host operating system details
  26.  */
  27.  
  28. #include <string.h>
  29. #include <stdlib.h>
  30. #include <unix.h>
  31. #include <fcntl.h>
  32. #include <TransDisplay.h>
  33.  
  34. #define HIGH_LOW  1
  35.  
  36. MenuHandle        mFile,mOptions,mfilter,mstrip;
  37. CursHandle        c;
  38. WindowRecord    wprogressRec;
  39. WindowPtr        wlist,wprogress;
  40. Point            bloc =    {40,40};
  41. Rect            prect;
  42.  
  43. SFReply        SFzipfd;
  44. FInfo        ffinfo;
  45.  
  46. Boolean        finishedflag,dirflag;
  47. Boolean        stripLFflag=false;
  48. Boolean        wlistflag=false;
  49. Boolean        choosefileflag=false;
  50. Boolean        TEXTfilterflag=false;
  51.  
  52. char        tstring[256],tfilename[256];
  53. long        zipoffset[100],progresscount,sizeblock,fpos;
  54. int            direntries,dindex,blockcount,numblocks;
  55.  
  56. typedef struct gifinfo
  57.     {
  58.         char    gif_signature[6];
  59.         int        screen_width;
  60.         int        screen_height;
  61.         char    color_resolution;
  62.     } gifinfo;
  63.  
  64. /* -------------------------------------------------------------------------- */
  65. /* stuff needed for exploding */
  66.  
  67. #define        LITERAL_TREE_ROOT    256
  68. #define        DISTANCE_TREE_ROOT     64
  69. #define        LENGTH_TREE_ROOT     64
  70.  
  71. typedef struct SF_Node
  72.     {
  73.         int        LChild;
  74.         int        RChild;
  75.     } SF_Node;
  76.  
  77. SF_Node            SF_Literal[LITERAL_TREE_ROOT + 1];
  78. SF_Node            SF_Distance[DISTANCE_TREE_ROOT + 1];;
  79. SF_Node            SF_Length[LENGTH_TREE_ROOT + 1];
  80.  
  81. typedef struct    SF_BuildRec
  82.     {
  83.         int        Len;
  84.         int        Val;
  85.         int        Code;
  86.     } SF_BuildRec;
  87.  
  88. int                NextFreeLiteral;
  89. int                NextFreeLength;
  90. int                NextFreeDistance;
  91. int                NumOfTrees;
  92. int                MinMatchLen;
  93. int                DictSize;
  94.  
  95. /* -------------------------------------------------------------------------- */
  96. /* -------------------------------------------------------------------------- */
  97. /*
  98.  * dearchiving code Copyright 1989 Samuel H. Smith;  All rights reserved
  99.  *
  100.  * Do not distribute modified versions without my permission.
  101.  * Do not remove or alter this notice or any other copyright notice.
  102.  * If you use this in your own program you must distribute source code.
  103.  * Do not use any of this in a commercial product.
  104.  *
  105.  */
  106.  
  107. #define CODE_VERSION  "UnZip:  Zipfile Extract v1.2 of 03-15-89;  (C) 1989 Samuel H. Smith"
  108.  
  109. typedef unsigned char byte;    /* code assumes UNSIGNED bytes */
  110. typedef long longint;
  111. typedef unsigned word;
  112. typedef char boolean;
  113.  
  114. #define STRSIZ 256
  115.  
  116. unsigned int in_size,out_size;
  117.  
  118. /* -------------------------------------------------------------------------- */
  119. /*
  120.  *                Zipfile layout declarations
  121.  */
  122.  
  123. typedef longint signature_type;
  124.  
  125.  
  126. #define LOCAL_FILE_HEADER_SIGNATURE  0x504B0304L
  127.  
  128.  
  129. typedef struct local_file_header {
  130.     word version_needed_to_extract;
  131.     word general_purpose_bit_flag;
  132.     int compression_method;
  133.     int last_mod_file_time;
  134.     int last_mod_file_date;
  135.     longint crc32;
  136.     longint compressed_size;
  137.     longint uncompressed_size;
  138.     int filename_length;
  139.     int extra_field_length;
  140. } local_file_header;
  141.  
  142.  
  143. #define CENTRAL_FILE_HEADER_SIGNATURE  0x504B0102L
  144.  
  145.  
  146. typedef struct central_directory_file_header {
  147.     word version_made_by;
  148.     word version_needed_to_extract;
  149.     word general_purpose_bit_flag;
  150.     word compression_method;
  151.     word last_mod_file_time;
  152.     word last_mod_file_date;
  153.     longint crc32;
  154.     longint compressed_size;
  155.     longint uncompressed_size;
  156.     word filename_length;
  157.     word extra_field_length;
  158.     word file_comment_length;
  159.     word disk_number_start;
  160.     word internal_file_attributes;
  161.     longint external_file_attributes;
  162.     longint relative_offset_local_header;
  163. } central_directory_file_header;
  164.  
  165.  
  166. #define END_CENTRAL_DIR_SIGNATURE  0x504B0506L
  167.  
  168.  
  169. typedef struct end_central_dir_record {
  170.     word number_this_disk;
  171.     word number_disk_with_start_central_directory;
  172.     word total_entries_central_dir_on_this_disk;
  173.     word total_entries_central_dir;
  174.     longint size_central_directory;
  175.     longint offset_start_central_directory;
  176.     word zipfile_comment_length;
  177. } end_central_dir_record;
  178.  
  179.  
  180.  
  181. /* -------------------------------------------------------------------------- */
  182. /*
  183.  * input file variables
  184.  *
  185.  */
  186.  
  187. #define INBUFSIZ 0x2000L
  188. char *inbuf;                        /* input file buffer - any size is legal */
  189. char *inptr;
  190.  
  191. int incnt;
  192. unsigned bitbuf;
  193. int bits_left;
  194. boolean zipeof;
  195.  
  196. int zipfd;
  197.  
  198. local_file_header lrec;
  199.  
  200.  
  201. /* -------------------------------------------------------------------------- */
  202. /*
  203.  * output stream variables
  204.  *
  205.  */
  206.  
  207. #define OUTBUFSIZ 0x6000L
  208. char    *outbuf;                      /* buffer for rle look-back */
  209. char    *outptr;
  210.  
  211. long            outpos;                /* absolute position in outfile */
  212. unsigned int    outcnt;                /* current position in outbuf */
  213.  
  214. int        outfd;
  215. char    filename[STRSIZ];
  216. char    extra[STRSIZ];
  217.  
  218. #define DLE 144
  219.  
  220. /* -------------------------------------------------------------------------- */
  221. /*
  222.  * shrink/reduce working storage
  223.  *
  224.  */
  225.  
  226. int        factor;
  227. byte    followers[256][64];
  228. byte    Slen[256];
  229.  
  230. #define    max_bits 13
  231. #define init_bits 9
  232. #define hsize 8192
  233. #define first_ent 257
  234. #define clear 256
  235.  
  236. int        *Prefix_of;
  237. byte    *Suffix_of;
  238. byte    *Stack;
  239.  
  240. int        codesize;
  241. int        maxcode;
  242. int        free_ent;
  243. int        maxcodemax;
  244. int        offset;
  245. int        sizex;
  246.  
  247. /* -------------------------------------------------------------------------- */
  248. void swap_bytes(wordp)
  249. word *wordp;
  250. /* convert intel style ╘short int╒ variable to host format */
  251. {
  252.     char *charp = (char *) wordp;
  253.     char temp;
  254.  
  255.     temp = charp[0];
  256.     charp[0] = charp[1];
  257.     charp[1] = temp;
  258. }
  259.  
  260. /* -------------------------------------------------------------------------- */
  261. void swap_lbytes(longp)
  262. longint *longp;
  263. /* convert intel style ╘long╒ variable to host format */
  264. {
  265.     char *charp = (char *) longp;
  266.     char temp[4];
  267.  
  268.     temp[3] = charp[0];
  269.     temp[2] = charp[1];
  270.     temp[1] = charp[2];
  271.     temp[0] = charp[3];
  272.  
  273.     charp[0] = temp[0];
  274.     charp[1] = temp[1];
  275.     charp[2] = temp[2];
  276.     charp[3] = temp[3];
  277. }
  278.  
  279.  
  280. /* -------------------------------------------------------------------------- */
  281. int FillBuffer()
  282.  /* fill input buffer if possible */
  283. {
  284.     extern local_file_header lrec;
  285.     unsigned int readsize;
  286.  
  287.     if (lrec.compressed_size <= 0 ) return (incnt = 0);
  288.  
  289.     if (lrec.compressed_size > (long) in_size) readsize = in_size;
  290.     else readsize = (int) lrec.compressed_size;
  291.     
  292.     incnt = read(zipfd, inbuf, readsize);
  293.  
  294.     lrec.compressed_size -= incnt;
  295.     inptr = inbuf;
  296.     return (incnt--);
  297. }
  298.  
  299. /* -------------------------------------------------------------------------- */
  300. int ReadByte(x)
  301. unsigned *x;
  302.  /* read a byte; return 8 if byte available, 0 if not */
  303. {    
  304.     /* counter for UpdateProgressWind    */
  305.     if(sizeblock == ++progresscount)
  306.     {
  307.         progresscount    =    0L;
  308.         UpdateProgressWind(numblocks,++blockcount);
  309.     }
  310.     
  311.     if (incnt-- == 0)
  312.         if (FillBuffer() == 0)
  313.             return 0;
  314.  
  315.     *x = *inptr++;
  316.     return 8;
  317. }
  318.  
  319.  
  320. /* -------------------------------------------------------------------------- */
  321. static unsigned mask_bits[] =
  322.         {0,     0x0001, 0x0003, 0x0007, 0x000f,
  323.                 0x001f, 0x003f, 0x007f, 0x00ff,
  324.                 0x01ff, 0x03ff, 0x07ff, 0x0fff,
  325.                 0x1fff, 0x3fff, 0x7fff, 0xffff
  326.         };
  327.  
  328. /* -------------------------------------------------------------------------- */
  329. int FillBitBuffer(bits)
  330. register int bits;
  331. {
  332.     /* get the bits that are left and read the next word */
  333.     unsigned temp;
  334.     register int result = bitbuf;
  335.     int sbits = bits_left;
  336.     bits -= bits_left;
  337.  
  338.     /* read next word of input */
  339.     bits_left = ReadByte(&bitbuf);
  340.     bitbuf    = bitbuf & 0x00FF;
  341.     bits_left += ReadByte(&temp);
  342.     bitbuf |= (temp << 8);
  343.     if (bits_left == 0)
  344.         zipeof = 1;
  345.  
  346.     /* get the remaining bits */
  347.     result = result | (int) ((bitbuf & mask_bits[bits]) << sbits);
  348.     bitbuf >>= bits;
  349.     bits_left -= bits;
  350.     return result;
  351. }
  352.  
  353. /* -------------------------------------------------------------------------- */
  354. #define READBIT(nbits,zdest) { if (nbits <= bits_left) { zdest = (int)(bitbuf & mask_bits[nbits]); bitbuf >>= nbits; bits_left -= nbits; } else zdest = FillBitBuffer(nbits);}
  355. /*
  356.  * macro READBIT(nbits,zdest)
  357.  *  {
  358.  *      if (nbits <= bits_left) {
  359.  *          zdest = (int)(bitbuf & mask_bits[nbits]);
  360.  *          bitbuf >>= nbits;
  361.  *          bits_left -= nbits;
  362.  *      } else
  363.  *          zdest = FillBitBuffer(nbits);
  364.  *  }
  365.  *
  366.  */
  367.  
  368.  
  369. /* -------------------------------------------------------------------------- */
  370. #include "crc32.h"
  371.  
  372. /* -------------------------------------------------------------------------- */
  373. void FlushOutput()
  374.  /* flush contents of output buffer */
  375. {
  376.     UpdateCRC(outbuf, outcnt);
  377.     write(outfd, outbuf, outcnt);
  378.     outpos = outpos + (long) outcnt;
  379.     outcnt = 0;
  380.     outptr = outbuf;
  381. }
  382.  
  383. /* -------------------------------------------------------------------------- */
  384. #define OUTB(intc) { *outptr++=intc; if (++outcnt==out_size) FlushOutput(); }
  385. /*
  386.  *  macro OUTB(intc)
  387.  *  {
  388.  *      *outptr++=intc;
  389.  *      if (++outcnt==out_size)
  390.  *          FlushOutput();
  391.  *  }
  392.  *
  393.  */
  394.  
  395. /* -------------------------------------------------------------------------- */
  396. void LoadFollowers()
  397. {
  398.     register int x;
  399.     register int i;
  400.  
  401.     for (x = 255; x >= 0; x--) 
  402.     {
  403.         READBIT(6,Slen[x]);
  404.         for (i = 0; i < Slen[x]; i++)
  405.         {
  406.             READBIT(8,followers[x][i]);
  407.         }
  408.     }
  409. }
  410.  
  411. /* -------------------------------------------------------------------------- */
  412. /*
  413.  * The Reducing algorithm is actually a combination of two
  414.  * distinct algorithms.  The first algorithm compresses repeated
  415.  * byte sequences, and the second algorithm takes the compressed
  416.  * stream from the first algorithm and applies a probabilistic
  417.  * compression method.
  418.  */
  419.  
  420. int L_table[] = {0, 0x7f, 0x3f, 0x1f, 0x0f};
  421.  
  422. int D_shift[] = {0, 0x07, 0x06, 0x05, 0x04};
  423. int D_mask[]  = {0, 0x01, 0x03, 0x07, 0x0f};
  424.  
  425. int B_table[] = {8, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5,
  426.          5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6,
  427.          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  428.          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
  429.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  430.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  431.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  432.          7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  433.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  434.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  435.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  436.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  437.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  438.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  439.          8, 8, 8, 8};
  440.  
  441. /* -------------------------------------------------------------------------- */
  442. void unReduce()
  443. /* expand probablisticly reduced data */
  444. {
  445.     register int    lchar;
  446.     register int    nchar;
  447.     int                ExState;
  448.     register int    V;
  449.     register int    Len;
  450.     int                ix,i,offset;
  451.     long            op;
  452.  
  453.     factor    =    lrec.compression_method - 1;
  454.     ExState    =    0;
  455.     lchar    =    0;
  456.     LoadFollowers();
  457.         
  458.     while (((outpos + outcnt) < lrec.uncompressed_size) && (!zipeof))
  459.     {
  460.         if (Slen[lchar] == 0)    READBIT(8,nchar)      /* ; */
  461.         
  462.         else
  463.         {
  464.             READBIT(1,nchar);
  465.             if (nchar != 0)    READBIT(8,nchar)          /* ; */
  466.  
  467.             else
  468.             {
  469.                 int follower;
  470.                 int bitsneeded = B_table[Slen[lchar]];
  471.                 READBIT(bitsneeded,follower);
  472.                 nchar = followers[lchar][follower];
  473.             }
  474.         }
  475.  
  476.         /* expand the resulting byte */
  477.         switch (ExState) 
  478.         {
  479.  
  480.         case 0:
  481.             if (nchar != DLE)    OUTB(nchar)            /* ; */
  482.             
  483.             else
  484.                 ExState = 1;
  485.                 
  486.             break;
  487.  
  488.         case 1:
  489.             if (nchar != 0) 
  490.             {
  491.                 V = nchar;
  492.                 Len = V & L_table[factor];
  493.                 if (Len == L_table[factor])    ExState = 2;
  494.                 else                        ExState = 3;
  495.             }
  496.             else 
  497.             {
  498.                 OUTB(DLE);
  499.                 ExState = 0;
  500.             }
  501.             break;
  502.  
  503.         case 2: 
  504.             {
  505.                 Len += nchar;
  506.                 ExState = 3;
  507.             }
  508.             break;
  509.  
  510.         case 3: 
  511.             {
  512.                 i = Len + 3;
  513.                 offset = (((V >> D_shift[factor]) &
  514.                                           D_mask[factor]) << 8) + nchar + 1;
  515.                 op = outpos + outcnt - offset;
  516.  
  517.                 /* special case- before start of file */
  518.                 while ((op < 0L) && (i > 0)) 
  519.                 {
  520.                     OUTB(0);
  521.                     op++;
  522.                     i--;
  523.                 }
  524.  
  525.                 /* normal copy of data from output buffer */
  526.                 {
  527.                     ix = (int) (op % out_size);
  528.  
  529.                     /* do a block memory copy if possible */
  530.                        if ( ((ix    +i) < out_size) && ((outcnt+i) < out_size) )
  531.                     {
  532.                         memcpy(outptr,&outbuf[ix],i);
  533.                         outptr += i;
  534.                         outcnt += i;
  535.                     }
  536.  
  537.                     /* otherwise copy byte by byte */
  538.                     else    while (i--) 
  539.                     {
  540.                         OUTB(outbuf[ix]);
  541.                         if (++ix >= out_size)    ix = 0;
  542.                     }
  543.                 }
  544.  
  545.                 ExState = 0;
  546.             }
  547.             break;
  548.         }
  549.  
  550.         /* store character for next iteration */
  551.         lchar = nchar;
  552.     }
  553. }
  554.  
  555. /* -------------------------------------------------------------------------- */
  556. /*
  557.  * Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm
  558.  * with partial clearing.
  559.  *
  560.  */
  561.  
  562. void partial_clear()
  563. {
  564.     extern int *Prefix_of;
  565.     register int pr;
  566.     register int cd;
  567.  
  568.     /* mark all nodes as potentially unused */
  569.     for (cd = first_ent; cd < free_ent; cd++)
  570.         *(Prefix_of + cd) |= 0x8000;
  571.  
  572.     /* unmark those that are used by other nodes */
  573.     for (cd = first_ent; cd < free_ent; cd++) {
  574.         pr = *(Prefix_of + cd) & 0x7fff;    /* reference to another node? */
  575.                 if (pr >= first_ent)            /* flag node as referenced */
  576.             *(Prefix_of +pr) &= 0x7fff;
  577.     }
  578.  
  579.     /* clear the ones that are still marked */
  580.     for (cd = first_ent; cd < free_ent; cd++)
  581.         if ((*(Prefix_of + cd) & 0x8000) != 0)
  582.             *(Prefix_of + cd) = -1;
  583.  
  584.     /* find first cleared node as next free_ent */
  585.         cd = first_ent;
  586.         while ((cd < maxcodemax) && (*(Prefix_of + cd) != -1))
  587.                 cd++;
  588.         free_ent = cd;
  589. }
  590.  
  591. /* -------------------------------------------------------------------------- */
  592. void unShrink()
  593. {
  594.    #define  GetCode(dest) READBIT(codesize,dest)
  595.  
  596.     extern int *Prefix_of;
  597.     extern byte *Suffix_of;
  598.     extern local_file_header lrec;
  599.     extern byte *Stack;
  600.     register int code;
  601.     register int stackp;
  602.     int finchar;
  603.     int oldcode;
  604.     int incode;
  605.     void partial_clear();
  606.  
  607.  
  608.     /* decompress the file */
  609.     maxcodemax = 1 << max_bits;
  610.     codesize = init_bits;
  611.     maxcode = (1 << codesize) - 1;
  612.     free_ent = first_ent;
  613.     offset = 0;
  614.     sizex = 0;
  615.  
  616.     for (code = maxcodemax; code > 255; code--)
  617.         *(Prefix_of + code) = -1;
  618.  
  619.     for (code = 255; code >= 0; code--)
  620.     {
  621.         *(Prefix_of + code) = 0;
  622.         *(Suffix_of + code) = code;
  623.     }
  624.     
  625.     GetCode(oldcode);
  626.     if (zipeof) return;
  627.     finchar = oldcode;
  628.  
  629.     OUTB(finchar);
  630.  
  631.     stackp = hsize;
  632.  
  633.     while (!zipeof) 
  634.     {    
  635.         GetCode(code);
  636.         if (zipeof) return;
  637.  
  638.         while (code == clear) 
  639.         {
  640.             GetCode(code);
  641.             switch (code) 
  642.             {
  643.  
  644.             case 1:
  645.                 {
  646.                     codesize++;
  647.                     if (codesize == max_bits)
  648.                             maxcode = maxcodemax;
  649.                     else
  650.                             maxcode = (1 << codesize) - 1;
  651.                 }
  652.                 break;
  653.  
  654.             case 2:
  655.                 partial_clear();
  656.                 break;
  657.                 
  658.             }
  659.  
  660.             GetCode(code);
  661.             if (zipeof) return;
  662.         }
  663.  
  664.  
  665.         /* special case for KwKwK string */
  666.         incode = code;
  667.         if (*(Prefix_of + code) == -1)
  668.         {
  669.             *(Stack + --stackp) = finchar;
  670.             code = oldcode;
  671.         }
  672.  
  673.  
  674.         /* generate output characters in reverse order */
  675.         while (code >= first_ent)
  676.         {
  677.             *(Stack + --stackp) = *(Suffix_of + code);
  678.             code = *(Prefix_of + code);
  679.         }
  680.  
  681.         finchar = *(Suffix_of + code);
  682.         *(Stack + --stackp) = finchar;
  683.  
  684.  
  685.         /* and put them out in forward order, block copy */
  686.         if ((hsize-stackp+outcnt) < out_size)
  687.         {
  688.             memcpy(outptr,Stack+stackp,hsize-stackp);
  689.             outptr += hsize-stackp;
  690.             outcnt += hsize-stackp;
  691.             stackp = hsize;
  692.         }
  693.  
  694.         /* output byte by byte if we can╒t go by blocks */
  695.         else while (stackp < hsize)
  696.                         OUTB(*(Stack + stackp++));
  697.  
  698.  
  699.         /* generate new entry */
  700.         code = free_ent;
  701.         if (code < maxcodemax)
  702.         {
  703.             *(Prefix_of + code) = oldcode;
  704.             *(Suffix_of + code) = finchar;
  705.  
  706.             do
  707.                 code++;
  708.             while ((code < maxcodemax) && (*(Prefix_of + code) != -1));
  709.  
  710.             free_ent = code;
  711.         }
  712.  
  713.         /* remember previous code */
  714.         oldcode = incode;
  715.     }
  716.  
  717. }
  718.  
  719. /* ------------------------------------------------------------------------- */
  720. void get_string(len,s)
  721. int len;
  722. char *s;
  723. {
  724.      read(zipfd, s, len);
  725.     s[len] = 0;
  726. }
  727.  
  728. /* ------------------------------------------------------------------------- */
  729. /*memcpy(to,from,count)
  730. register char *to,*from;
  731. register unsigned int count;
  732. {
  733.     for(;count>0;--count,++to,++from)
  734.         *to=*from;
  735. }*/
  736.  
  737. /* -------------------------------------------------------------------------- */
  738. /* -------------------------------------------------------------------------- */
  739. /*
  740.  *  Exploding code derived from Turbo Pascal v. 5.0 source ⌐ R.P. Byrne
  741.  *  (version 2.0 ╤ July 31, 1989)
  742.  *
  743.  */
  744.  
  745. /* -------------------------------------------------------------------------- */
  746. Bad_SF_Tree()
  747. {
  748.     close(outfd);
  749.     CloseProgressWind();
  750.     DisplayString("\p --  bad Shannon-Fano decode tree  --  file skipped\015");    
  751. }
  752.  
  753. /* -------------------------------------------------------------------------- */
  754. Boolean Add_SF_SubTree(SF_TreePtr,SF_NextFreePtr,CurrNode,SF_Code,SF_Len,SF_Val)
  755. SF_Node        (*SF_TreePtr)[];
  756. int            *SF_NextFreePtr;
  757. int            CurrNode;
  758. int            SF_Code;
  759. int            SF_Len;
  760. int            SF_Val;
  761. {
  762.     int        i;
  763.     
  764.     for (i=(SF_Len - 1); i>=1; i--)
  765.     {
  766.         if (0 >= CurrNode)
  767.         {
  768.             Bad_SF_Tree();
  769.             return(true);
  770.         }
  771.         
  772.         if ((SF_Code >> i) & 0x0001)
  773.         {
  774.             if (-999 == (*SF_TreePtr)[CurrNode].RChild)
  775.             {
  776.                 (*SF_TreePtr)[CurrNode].RChild = *SF_NextFreePtr;
  777.                 (*SF_NextFreePtr)--;
  778.             }
  779.             CurrNode    =    (*SF_TreePtr)[CurrNode].RChild;
  780.         }
  781.         
  782.         else
  783.         {
  784.             if (-999 == (*SF_TreePtr)[CurrNode].LChild)
  785.             {
  786.                 (*SF_TreePtr)[CurrNode].LChild = *SF_NextFreePtr;
  787.                 (*SF_NextFreePtr)--;
  788.             }
  789.             CurrNode    =    (*SF_TreePtr)[CurrNode].LChild;
  790.         }
  791.     }
  792.     
  793.     if (SF_Code & 0x0001)
  794.     {
  795.         if (-999 != (*SF_TreePtr)[CurrNode].RChild)
  796.         {
  797.             Bad_SF_Tree();
  798.             return(true);
  799.         }
  800.         
  801.         else    (*SF_TreePtr)[CurrNode].RChild = -SF_Val;
  802.     }
  803.     
  804.     else
  805.     {
  806.         if (-999 != (*SF_TreePtr)[CurrNode].LChild)
  807.         {
  808.             Bad_SF_Tree();
  809.             return(true);
  810.         }
  811.         
  812.         else    (*SF_TreePtr)[CurrNode].LChild = -SF_Val;
  813.     }
  814.     
  815.     return (false);        
  816. }
  817.  
  818. /* -------------------------------------------------------------------------- */
  819. Boolean Construct_SF_Tree(SF_TreePtr,SF_NextFreePtr,treesize)
  820. SF_Node        (*SF_TreePtr)[];
  821. int            *SF_NextFreePtr;
  822. int            treesize;
  823. {
  824.     static int swapsize[]={9,5,3,2,1};
  825.     
  826.     SF_BuildRec        SF_Build[256];
  827.     SF_BuildRec        tempnode;
  828.     
  829.     int        OneByte;
  830.     char    CodeLen;
  831.     char    CodeCount;
  832.     
  833.     int        SF_Table_Codes;
  834.     int        SF_Build_Idx;
  835.     int        BuildCount;
  836.     
  837.     unsigned int        Code;
  838.     unsigned int        CodeIncrement;
  839.     int                    LastBitLength;
  840.     
  841.     register int        i,j,k,s;
  842.     int                 w,tLen,tVal;
  843.  
  844.     SF_Build_Idx    =    0;
  845.     BuildCount        =    0;
  846.     if(0 == ReadByte(&SF_Table_Codes))
  847.         {
  848.             DisplayString("\p -- unexpected end of file  --  file skipped");
  849.             return(true);
  850.         }
  851.         
  852.     for (i=0; i<=SF_Table_Codes; i++)
  853.     {
  854.         if(0 == ReadByte(&OneByte))
  855.         {
  856.             DisplayString("\p -- unexpected end of file  --  file skipped");
  857.             return(true);
  858.         }
  859.         CodeLen        =    (OneByte & 0x000F) + 1;
  860.         CodeCount    =    (OneByte >> 4) & 0x000F;
  861.         
  862.         for (j=0; j<=CodeCount; j++)
  863.         {
  864.             SF_Build[SF_Build_Idx].Len    =    CodeLen;
  865.             SF_Build[SF_Build_Idx].Val    =    SF_Build_Idx;
  866.             SF_Build_Idx++;
  867.         }
  868.     }
  869.     BuildCount    =    SF_Build_Idx - 1;
  870.     
  871.     /*    Shell sort of tree leaves    */
  872.     for (w=0; w<5; w++)
  873.     {
  874.         k    =    swapsize[w];
  875.         s    =    -k;
  876.         for (i=k; i<=BuildCount; ++i)
  877.         {
  878.             tLen    =    SF_Build[i].Len;
  879.             tVal    =    SF_Build[i].Val;
  880.             j    =    i -    k;
  881.             if (s==0)
  882.             {
  883.                 s    =    -k;
  884.                 s++;
  885.                 SF_Build[s].Len        =    tLen;
  886.                 SF_Build[s].Val        =    tVal;
  887.             }
  888.             while (((tLen < SF_Build[j].Len) ||
  889.                     ((tLen == SF_Build[j].Len) && (tVal < SF_Build[j].Val)))
  890.                     && j>=0 && j<=BuildCount+1)
  891.             {
  892.                 SF_Build[j+k].Len    =    SF_Build[j].Len;
  893.                 SF_Build[j+k].Val    =    SF_Build[j].Val;
  894.                 j    =    j - k;
  895.             }
  896.             SF_Build[j+k].Len    =    tLen;
  897.             SF_Build[j+k].Val    =    tVal;
  898.         }
  899.     }
  900.     
  901.     Code            =    0;
  902.     CodeIncrement    =    0;
  903.     LastBitLength    =    0;
  904.     
  905.     for (i=BuildCount; i>=0; i--)
  906.     {
  907.         Code    =    Code    +    CodeIncrement;
  908.         
  909.         if(SF_Build[i].Len != LastBitLength)
  910.         {
  911.             LastBitLength    =    SF_Build[i].Len;
  912.             CodeIncrement    =    1 << (16 - LastBitLength);
  913.         }
  914.         SF_Build[i].Code    =    Code >> (16 - SF_Build[i].Len);
  915.         
  916. /*        sprintf(tstring,"\r%3d  %3d  %3d  %4X",i,SF_Build[i].Len,SF_Build[i].Val,SF_Build[i].Code);
  917.         DisplayString(CtoPstr(tstring));    */
  918.         
  919.         if(Add_SF_SubTree(    SF_TreePtr,
  920.                             SF_NextFreePtr,
  921.                             treesize,
  922.                             SF_Build[i].Code,
  923.                             SF_Build[i].Len,
  924.                             SF_Build[i].Val    )) return (true);
  925.     }
  926. /*    for (i=0;i<=treesize;i++)
  927.         fprintf(sftrees,"\r%3d  %3d  %3d",i,(*SF_TreePtr)[i].LChild,(*SF_TreePtr)[i].RChild);
  928.     fprintf(sftrees,"\r\r"); */
  929.     
  930.     return (false);
  931. }
  932.  
  933. /* -------------------------------------------------------------------------- */
  934. Boolean Init_Explode()
  935. {
  936.     int        i;
  937.     
  938.     DictSize    =    (((lrec.general_purpose_bit_flag >> 1) & 0x01) * 4096) + 4096;
  939.     NumOfTrees    =     ((lrec.general_purpose_bit_flag >> 2) & 0x01) + 2;
  940.     MinMatchLen    =    NumOfTrees;
  941.     
  942.     for (i=0; i<=LENGTH_TREE_ROOT; i++)
  943.     {
  944.         SF_Length[i].LChild        =    -999;
  945.         SF_Length[i].RChild        =    -999;
  946.     }
  947.     NextFreeLength    =    LENGTH_TREE_ROOT - 1;
  948.     
  949.     for (i=0; i<=DISTANCE_TREE_ROOT; i++)
  950.     {
  951.         SF_Distance[i].LChild    =    -999;
  952.         SF_Distance[i].RChild    =    -999;
  953.     }
  954.     NextFreeDistance    =    DISTANCE_TREE_ROOT - 1;
  955.     
  956.     if(3==NumOfTrees) 
  957.     {
  958.         for (i=0; i<=LITERAL_TREE_ROOT; i++)
  959.         {
  960.             SF_Literal[i].LChild =    -999;
  961.             SF_Literal[i].RChild =    -999;
  962.         }
  963.         NextFreeLiteral    =    LITERAL_TREE_ROOT - 1;
  964.         if(Construct_SF_Tree(&SF_Literal,&NextFreeLiteral,LITERAL_TREE_ROOT)) return(true);
  965.     }
  966.  
  967.     if(Construct_SF_Tree(&SF_Length,&NextFreeLength,LENGTH_TREE_ROOT)) return(true);
  968.     if(Construct_SF_Tree(&SF_Distance,&NextFreeDistance,DISTANCE_TREE_ROOT)) return(true);
  969.     
  970.     return (false);
  971. }
  972.  
  973. /* -------------------------------------------------------------------------- */
  974. Boolean Decode_SF_Data(SF_TreePtr,CurrNode,OutputPtr)
  975. register SF_Node    (*SF_TreePtr)[];
  976. register int        CurrNode;
  977. int                    *OutputPtr;
  978. {
  979.     register int    OneBit;
  980.  
  981.     while (0 < CurrNode)
  982.     {
  983.         READBIT(1,OneBit);
  984.         
  985.         if (OneBit)
  986.         {
  987.             if (-999 == (*SF_TreePtr)[CurrNode].RChild)
  988.             {
  989.                 Bad_SF_Tree();
  990.                 return(true);
  991.             }            
  992.             
  993.             else    CurrNode = (*SF_TreePtr)[CurrNode].RChild;
  994.         }
  995.         
  996.         else
  997.         {
  998.             if (-999 == (*SF_TreePtr)[CurrNode].LChild)
  999.             {
  1000.                 Bad_SF_Tree();
  1001.                 return(true);
  1002.             }            
  1003.             
  1004.             else    CurrNode = (*SF_TreePtr)[CurrNode].LChild;
  1005.         }
  1006.     }
  1007.     *OutputPtr    =    -CurrNode;    
  1008.     return (false);
  1009. }            
  1010.  
  1011. /* -------------------------------------------------------------------------- */
  1012.  Boolean Explode()
  1013.  {
  1014.     extern byte *Stack;
  1015.     
  1016.     int            DistVal;
  1017.     int            Literal;
  1018.     int            Length;
  1019.     int            Distance;
  1020.     int            NBits;
  1021.     int            Mask;
  1022.         
  1023.     register int    StackIdx;
  1024.     register int    StackStart;
  1025.     register int    OneByte;
  1026.     register int    i;
  1027.  
  1028.     Boolean        LiteralTreeflag;
  1029.  
  1030.     if(Init_Explode()) return;
  1031.     
  1032.     for (StackIdx=0; StackIdx<hsize+1; StackIdx++) *(Stack + StackIdx) = 0;
  1033.     StackIdx    =    0;
  1034.  
  1035.     LiteralTreeflag    =    (3 == NumOfTrees);
  1036.     
  1037.     if ((8192 == DictSize))
  1038.     {
  1039.         NBits    =    7;
  1040.         Mask    =    0x1FFF;
  1041.     }
  1042.     else
  1043.     {
  1044.         NBits    =    6;
  1045.         Mask    =    0x0FFF;
  1046.     }
  1047.     
  1048.     while ((!zipeof) && ((outpos + outcnt) < lrec.uncompressed_size))
  1049.     {
  1050.         READBIT(1,OneByte);
  1051.         if (OneByte)
  1052.         {
  1053.             if(LiteralTreeflag)
  1054.             { 
  1055.                 if(Decode_SF_Data(&SF_Literal,LITERAL_TREE_ROOT,&Literal)) return (true);
  1056.             }
  1057.             else    READBIT(8,Literal);
  1058.             
  1059.             OUTB(Literal);
  1060.             Stack[StackIdx]    =    (char) Literal;
  1061.             if(DictSize == ++StackIdx) StackIdx = 0;
  1062.         }
  1063.         
  1064.         else
  1065.         {        
  1066.             READBIT(NBits,Distance);
  1067.             if(Decode_SF_Data(&SF_Distance,DISTANCE_TREE_ROOT,&DistVal)) return (true);
  1068.             Distance    =    (Distance | (DistVal << NBits)) & Mask;
  1069.             
  1070.             if(Decode_SF_Data(&SF_Length,LENGTH_TREE_ROOT,&Length)) return (true);
  1071.             
  1072.             if (63 == Length)
  1073.             {
  1074.                 READBIT(8,i);
  1075.                 Length    =    Length + i;
  1076.             }
  1077.             
  1078.             i            =    Length + MinMatchLen;
  1079.             StackStart    =    StackIdx - (Distance + 1);
  1080.             if(0 > StackStart) StackStart = StackStart + DictSize;
  1081.             
  1082.             while (i-- > 0)
  1083.             {
  1084.                 OUTB(Stack[StackStart]);
  1085.                 Stack[StackIdx]    =    Stack[StackStart];
  1086.                 if(DictSize == ++StackIdx)        StackIdx = 0;
  1087.                 if(DictSize == ++StackStart)    StackStart = 0;
  1088.             }
  1089.         }
  1090.     }
  1091.     return (false);    
  1092. }
  1093.  
  1094. /* -------------------------------------------------------------------------- */
  1095. /* -------------------------------------------------------------------------- */ 
  1096. OSErr freeSpaceOnVol(vRef,pfreeBytes)
  1097. int             vRef;
  1098. unsigned long    *pfreeBytes;
  1099. {
  1100.     HVolumeParam    HPB;
  1101.     OSErr            err;
  1102.     long            temp;
  1103.     
  1104.     HPB.ioNamePtr    =    0L;
  1105.     HPB.ioVRefNum    =    vRef;
  1106.     HPB.ioVolIndex    =    0;
  1107.     err                =    PBHGetVInfo(&HPB,false);
  1108.     /*    modification of July 14, 1990 - UnZip 1.02c to eliminate sign extension
  1109.         problem with HPB.ioVFrBlk which resulted in a negative number if the 
  1110.         nnumber of free blocks exceeded 32767                                    */
  1111.     temp            =    HPB.ioVFrBlk;
  1112.     if(0 > temp)    temp = 65536L + temp;
  1113.     if(err==noErr) *pfreeBytes = (unsigned long) temp * HPB.ioVAlBlkSiz;
  1114.     else           *pfreeBytes = 0L;
  1115.     
  1116. /*    Monitor("HPB.ioVAlBlkSiz",(int) HPB.ioVAlBlkSiz,"HPB.ioVFrBlk",(int) HPB.ioVFrBlk,"temp",temp);*/
  1117.  
  1118.     return(err);
  1119. }
  1120.  
  1121. /* ------------------------------------------------------------------------- */
  1122. Monitor(s1,v1,s2,v2,s3,v3)
  1123. /* debugging routine to monitor variables    */
  1124. char    s1[32],s2[32],s3[32];
  1125. int        v1,v2;
  1126. long    v3;
  1127. {
  1128.     char    ts1[60],ts2[60],ts3[60];
  1129.     sprintf(ts1,"%10d  %s",v1,s1);
  1130.     sprintf(ts2,"%10d  %s",v2,s2);
  1131.     sprintf(ts3,"%10ld  %s",v3,s3);
  1132.     ParamText(CtoPstr(ts1),CtoPstr(ts2),CtoPstr(ts3),"\p");
  1133.     Alert(103,nil);
  1134. }
  1135.  
  1136. /* -------------------------------------------------------------------------- */
  1137. InitProgressWind(dearchivingtype)
  1138. char    *dearchivingtype;
  1139. {
  1140.     int    width;
  1141.     
  1142.     wprogress    =    GetNewWindow(102,&wprogressRec,-1L);
  1143.     SetPort(wprogress);
  1144.     sprintf(tstring,"%s : %s  %ld \304> %ld bytes",
  1145.             dearchivingtype,
  1146.             filename,
  1147.             lrec.compressed_size,
  1148.             lrec.uncompressed_size);
  1149.     TextFont(150);
  1150.     TextSize(9);
  1151.     TextFace(bold);
  1152.     width    =    StringWidth(CtoPstr(tstring));
  1153.     MoveTo(((416-width)/2),15);
  1154.     DrawString(tstring);
  1155.     SetRect(&prect,38,22,380,40);
  1156.     FrameRect(&prect);
  1157.     
  1158.     numblocks        =    20;
  1159.     sizeblock        =    lrec.compressed_size/20L;
  1160.     if(50000L > lrec.compressed_size) 
  1161.     {
  1162.         sizeblock    =     lrec.compressed_size/10L;
  1163.         numblocks    =    10;
  1164.     }
  1165.     if(10000L > lrec.compressed_size) 
  1166.     {
  1167.         sizeblock    =     lrec.compressed_size/4L;
  1168.         numblocks    =    4;
  1169.     }
  1170.     if( 2000L > lrec.compressed_size)
  1171.     {
  1172.         sizeblock    =    lrec.compressed_size/2L;
  1173.         numblocks    =    2;
  1174.     }
  1175.     progresscount    =    0L;
  1176.     blockcount        =    0;
  1177.     PenPat(gray);
  1178. }
  1179.  
  1180. /* -------------------------------------------------------------------------- */
  1181. UpdateProgressWind(numblocks,blockcount)
  1182. int    numblocks,blockcount;
  1183. {
  1184.     Rect    r;
  1185. /*    if(blockcount > numblocks) blockcount = numblocks;    */
  1186.     SetRect(&r,(39+(blockcount-1)*340/numblocks),23,(39+blockcount*340/numblocks),39);
  1187.     PaintRect(&r);        
  1188. }
  1189.  
  1190. /* -------------------------------------------------------------------------- */
  1191. CloseProgressWind()
  1192. {
  1193.     CloseWindow(wprogress);
  1194. }
  1195.  
  1196. /* -------------------------------------------------------------------------- */
  1197. Boolean check_abort()
  1198. {
  1199.     EvQElPtr    eq_p;
  1200.     Boolean        f_found=false;
  1201.     
  1202.     eq_p    =    (EvQElPtr)(EventQueue.qHead);
  1203.     while(true)
  1204.     {
  1205.         if((eq_p->evtQWhat==keyDown || eq_p->evtQWhat == autoKey) &&
  1206.            (eq_p->evtQModifiers & cmdKey) && (eq_p->evtQMessage & charCodeMask) == '.')
  1207.            {
  1208.                    Dequeue((QElemPtr)eq_p,&EventQueue);
  1209.                    f_found    = true;
  1210.                }
  1211.         if(eq_p == (EvQElPtr)EventQueue.qTail)    break;
  1212.         eq_p    =    (EvQEl *)(eq_p->qLink);
  1213.     }
  1214.     return (f_found);
  1215. }
  1216.  
  1217. /* -------------------------------------------------------------------------- */
  1218. void set_file_time() 
  1219. {
  1220.     HFileInfo        FiInfo;
  1221.     unsigned char    tfname[256];
  1222.     OSErr            result;
  1223.     DateTimeRec        dtr;
  1224.     long            seconds;
  1225.     
  1226.     strcpy(tstring,filename);
  1227.     CtoPstr(tstring);
  1228.     memcpy(tfname,tstring,256);
  1229.     FiInfo.ioNamePtr    =    tfname;
  1230.     FiInfo.ioVRefNum    =    0;
  1231.     FiInfo.ioFVersNum    =    0;
  1232.     FiInfo.ioFDirIndex    =    0;
  1233.     
  1234.     result    =    PBGetFInfo(&FiInfo,false);
  1235.     
  1236.     dtr.day        =      lrec.last_mod_file_date & 0x1F;
  1237.     dtr.month    =     (lrec.last_mod_file_date >> 5) & 0x0F;
  1238.     dtr.year    =    ((lrec.last_mod_file_date >> 9) & 0x7F) + 1980;
  1239.     
  1240.     dtr.second    =    0;
  1241.     dtr.minute    =    (lrec.last_mod_file_time >> 5) & 0x3F;
  1242.     dtr.hour    =    (lrec.last_mod_file_time >>11) & 0x1F;
  1243.     dtr.second    = 2*(lrec.last_mod_file_time & 0x1F);
  1244.     
  1245.     Date2Secs(&dtr,&seconds);
  1246.     FiInfo.ioFlCrDat    =    seconds;
  1247.     FiInfo.ioFlMdDat    =    seconds;
  1248.     result    =    PBSetFInfo(&FiInfo,false);    
  1249. }
  1250.  
  1251. /* -------------------------------------------------------------------------- */
  1252. int create_output_file()
  1253. /* return non-0 if creat failed */
  1254. {
  1255.     extern            local_file_header lrec;
  1256.     long            freebytes;
  1257.     int                filerr;
  1258.     
  1259.     freeSpaceOnVol(SFzipfd.vRefNum,&freebytes);
  1260.     if(lrec.uncompressed_size > freebytes)
  1261.     {
  1262.         sprintf(tstring,"***********: %-12s  --  no space on volume  --  file skipped",filename);
  1263.         DisplayString(CtoPstr(tstring));
  1264.         return(1);
  1265.     }
  1266.     
  1267.     outfd = creat(filename, O_CREAT | O_RDWR | O_BINARY);
  1268.  
  1269.     if (outfd == EOF) 
  1270.     {
  1271.         sprintf(tstring,"***********: %-12s  --  can't create output file  --  file skipped",filename);
  1272.         DisplayString(CtoPstr(tstring));
  1273.         return(1);
  1274.     }
  1275.         
  1276.     strcpy(tstring,filename);
  1277.     GetFInfo(CtoPstr(tstring),0,&ffinfo);
  1278.     ffinfo.fdCreator    =    'pZIP';
  1279.     ffinfo.fdType        =    'TEXT';
  1280.     if((0L<zipoffset[dindex]) && (NULL==strstr(filename,".GIF")) && (NULL==strstr(filename,".gif"))) ffinfo.fdType='pBIN';
  1281.     SetFInfo(tstring,0,&ffinfo);
  1282.     
  1283. /*  write a single byte at EOF to pre-allocate the file */ 
  1284.     lseek(outfd, lrec.uncompressed_size-1L, SEEK_SET);
  1285.     
  1286.     filerr    =    write(outfd, "?", 1);
  1287.     
  1288.     lseek(outfd, 0L, SEEK_SET);
  1289.     return(0);
  1290. }
  1291.  
  1292. /* ------------------------------------------------------------------------- */
  1293. extract_member()
  1294. {
  1295.     extern    local_file_header lrec;
  1296.     
  1297.     gifinfo         gi;
  1298.     char        colors;
  1299.     int            ncolors;
  1300.     long        freebytes;
  1301.     
  1302.     unsigned b;
  1303.     FILE    *in,*out;
  1304.     int        ch;
  1305.  
  1306.     bits_left    =    0;
  1307.     bitbuf        =    0;
  1308.     incnt        =    0;
  1309.     outpos        =    0L;
  1310.     outcnt        =    0;
  1311.     outptr        =    outbuf;
  1312.     zipeof        =    0;
  1313.     crc32val    =    0xFFFFFFFFL;
  1314.     
  1315.     /* create the output file with READ and WRITE permissions */
  1316.     
  1317.     if(7>lrec.compression_method)
  1318.     {
  1319.         if (create_output_file())
  1320.         {
  1321.             DisplayLn();
  1322.             SysBeep(1);
  1323.             return(1);
  1324.         } 
  1325.     }
  1326.  
  1327.     switch (lrec.compression_method) 
  1328.     {
  1329.  
  1330.     case 0:        /* stored */
  1331.         {
  1332.             sprintf(tstring," Extracting: %-12s ", filename);
  1333.             DisplayString(CtoPstr(tstring));
  1334.             
  1335.             InitProgressWind("Extracting");
  1336.             while (ReadByte(&b)) OUTB(b);
  1337.             CloseProgressWind();
  1338.         }
  1339.         break;
  1340.  
  1341.     case 1: 
  1342.         {
  1343.             sprintf(tstring,"UnShrinking: %-12s ", filename);
  1344.             DisplayString(CtoPstr(tstring));
  1345.  
  1346.             InitProgressWind("UnShrinking");
  1347.             unShrink();
  1348.             CloseProgressWind();
  1349.         }
  1350.         break;
  1351.  
  1352.     case 2:
  1353.     case 3:
  1354.     case 4:
  1355.     case 5:
  1356.         {
  1357.             sprintf(tstring,"  Expanding: %-12s ",filename);
  1358.             DisplayString(CtoPstr(tstring));
  1359.  
  1360.             InitProgressWind("Expanding");
  1361.             unReduce();
  1362.             CloseProgressWind();
  1363.         }
  1364.         break;
  1365.         
  1366.     case 6:
  1367.         {
  1368.             sprintf(tstring,"  Exploding: %-12s ",filename);
  1369.             DisplayString(CtoPstr(tstring));
  1370.             InitProgressWind("Exploding");
  1371.             if(Explode()) return;
  1372.             CloseProgressWind();
  1373.         }
  1374.         break;
  1375.         
  1376.     default:
  1377.         {
  1378.             sprintf(tstring,"           : %-12s  --  unknown compression method  --  file skipped\015",filename);
  1379.             DisplayString(CtoPstr(tstring));
  1380.         }
  1381.     }
  1382.     
  1383.     if(6<lrec.compression_method) return;
  1384.     
  1385.     /* write the last partial buffer, if any */
  1386.     if (outcnt > 0)
  1387.     {
  1388.         UpdateCRC(outbuf, outcnt);
  1389.         write(outfd, outbuf, outcnt);
  1390.     }
  1391.  
  1392.     crc32val = -1 - crc32val;
  1393.  
  1394.     if (crc32val != lrec.crc32)
  1395.     {
  1396.         sprintf(tstring," --  Bad CRC %08lX  (should be %08lX)", lrec.crc32, crc32val);
  1397.         DisplayString(CtoPstr(tstring));
  1398.     }
  1399.     else     DisplayString("\p --  successful");
  1400.  
  1401.     /* if file ended in '.GIF' or '.gif' display additional GIF file info */
  1402.     if((NULL!=strstr(filename,".GIF")) || (NULL!=strstr(filename,".gif")))
  1403.     {
  1404.         lseek(outfd,0L,0L);
  1405.         read(outfd,tstring,sizeof(gifinfo));
  1406.         memcpy(&gi,tstring,sizeof(gifinfo));
  1407.         swap_bytes(&gi.screen_width);
  1408.         swap_bytes(&gi.screen_height);
  1409.         colors    =    gi.color_resolution & '\007';
  1410.         ncolors    =    1 << (1+(int) colors);
  1411.         sprintf(tstring,"\015                           --  GIF file:  %dx%d  %d colors",gi.screen_width,gi.screen_height,ncolors);
  1412.         DisplayString(CtoPstr(tstring));        
  1413.     }
  1414.     
  1415.     close(outfd);
  1416.  
  1417.     /* strip linefeeds from text files if stripLFflag = true */
  1418.     if (stripLFflag && (0>zipoffset[dindex]))
  1419.     {
  1420.         freeSpaceOnVol(SFzipfd.vRefNum,&freebytes);
  1421.         if(lrec.uncompressed_size > freebytes)
  1422.         {
  1423.             DisplayString("\p\015                           --  no space on volume for LF stripped file");
  1424.         }
  1425.         else
  1426.         {
  1427.             DisplayString("\p\015                           --  stripping LF's ");
  1428.             in    =    fopen(filename,"rb");
  1429.             out    =    fopen("pZIPtemp01","wb");
  1430.  
  1431.             if (out != NULL)
  1432.             {
  1433.                 strcpy(tstring,"pZIPtemp01");
  1434.                 GetFInfo(CtoPstr(tstring),0,&ffinfo);
  1435.                 ffinfo.fdCreator    =    'pZIP';
  1436.                 ffinfo.fdType        =    'TEXT';
  1437.                 SetFInfo(tstring,0,&ffinfo);
  1438.                 outcnt    =    0;
  1439.                 outptr    =    outbuf;
  1440.             
  1441.                 while ((ch=getc(in)) != EOF)  
  1442.                     if('\012' != ch)
  1443.                     {
  1444.                         *outptr++    =    ch;
  1445.                         if(++outcnt==out_size)
  1446.                         {
  1447.                             fwrite(outbuf,1,out_size,out);
  1448.                             outcnt    =    0;
  1449.                             outptr    =    outbuf;
  1450.                         }
  1451.                     }
  1452.                 
  1453.                 /*    write the last partial buffer, if any    */
  1454.                 if (outcnt > 0)    fwrite (outbuf,1,outcnt,out);
  1455.  
  1456.                 fclose(in);
  1457.                 fclose(out);
  1458.                 remove(filename);
  1459.                 rename("pZIPtemp01",filename);
  1460.                 DisplayString("\p --  successful");
  1461.             }
  1462.             else
  1463.             {    
  1464.                 DisplayString("\p\015                       --  error opening LF stripped file  --  skipped");    
  1465.             }
  1466.  
  1467.         }
  1468.     }
  1469.         
  1470.     /* set output file date and time */
  1471.     set_file_time();
  1472.     DisplayLn();
  1473. }
  1474.  
  1475. /* ------------------------------------------------------------------------- */
  1476. void process_local_file_header()
  1477. {
  1478.     extern local_file_header lrec;
  1479.     char temp[256];
  1480.     
  1481.     read(zipfd, tstring, sizeof(lrec));
  1482.     memcpy(&lrec,tstring,sizeof(lrec));
  1483.  
  1484.     swap_bytes(&lrec.filename_length);
  1485.     swap_bytes(&lrec.extra_field_length);
  1486.     swap_lbytes(&lrec.compressed_size);
  1487.     swap_lbytes(&lrec.uncompressed_size);
  1488.     swap_bytes(&lrec.last_mod_file_time);
  1489.     swap_bytes(&lrec.last_mod_file_date);
  1490.     swap_bytes(&lrec.compression_method);
  1491.     swap_bytes(&lrec.general_purpose_bit_flag);
  1492.     swap_lbytes(&lrec.crc32);
  1493.     
  1494.     get_string(lrec.filename_length, filename);
  1495.     get_string(lrec.extra_field_length, extra);
  1496.     
  1497.     if(TEXTfilterflag && (0L<zipoffset[dindex]) && (NULL==strstr(filename,".GIF")) && (NULL==strstr(filename,".gif"))) return;
  1498.     
  1499.     if (choosefileflag)
  1500.     {
  1501.         strcpy(tstring,"Dearchive ╥");
  1502.         strcat(tstring,filename);
  1503.         strcat(tstring,"╙?");
  1504.         ParamText(CtoPstr(tstring),"\p","\p","\p");
  1505.         InitCursor();
  1506.         if(1==Alert (102,nil)) 
  1507.         {
  1508.             c    =    GetCursor(watchCursor);
  1509.             SetCursor(*c);
  1510.             extract_member();
  1511.         }
  1512.     }
  1513.     else extract_member();
  1514. }
  1515.  
  1516. /* -------------------------------------------------------------------------- */
  1517. long process_central_file_header()
  1518. {
  1519.     central_directory_file_header rec;
  1520.     char filename[STRSIZ];
  1521.     char extra[STRSIZ];
  1522.     char comment[STRSIZ];
  1523.     static char *method[8]={"     Stored","     Shrunk","   Reduced1","   Reduced2","   Reduced3","   Reduced4","   Imploded","    Unknown"};
  1524.     static char *ny[2]={" no","yes"};
  1525.     static char *mo[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
  1526.     long    offset;
  1527.     int        day,month,year,hour,minute,second;
  1528.     
  1529.     if (dirflag)
  1530.     {
  1531.         memcpy(&rec,inbuf+incnt,sizeof(rec));
  1532.         incnt    =    incnt + sizeof(rec);
  1533.     }
  1534.     else
  1535.     {
  1536.         read(zipfd,tstring,sizeof(rec));
  1537.         memcpy(&rec,tstring,sizeof(rec));
  1538.     }
  1539.  
  1540.     swap_bytes(&rec.compression_method);
  1541.     swap_lbytes(&rec.compressed_size);
  1542.     swap_lbytes(&rec.uncompressed_size);
  1543.     swap_bytes(&rec.last_mod_file_time);
  1544.     swap_bytes(&rec.last_mod_file_date);
  1545.     swap_lbytes(&rec.crc32);
  1546.     swap_bytes(&rec.internal_file_attributes);
  1547.     swap_bytes(&rec.filename_length);
  1548.     swap_bytes(&rec.extra_field_length);
  1549.     swap_bytes(&rec.file_comment_length);
  1550.     swap_lbytes(&rec.relative_offset_local_header);
  1551.  
  1552.     if (dirflag)
  1553.     {
  1554.         memcpy(filename,inbuf+incnt,rec.filename_length);
  1555.         filename[rec.filename_length]    =    0;
  1556.         incnt    =    incnt + rec.filename_length;
  1557.         memcpy(extra,inbuf+incnt,rec.extra_field_length);
  1558.         extra[rec.extra_field_length]    =    0;
  1559.         incnt    =    incnt + rec.extra_field_length;
  1560.         memcpy(comment,inbuf+incnt,rec.file_comment_length);
  1561.         comment[rec.file_comment_length]    =    0;
  1562.         incnt    =    incnt + rec.file_comment_length;
  1563.     }
  1564.     else
  1565.     {
  1566.         get_string(rec.filename_length,filename);
  1567.         get_string(rec.extra_field_length,extra);
  1568.         get_string(rec.file_comment_length,comment);
  1569.     }
  1570.     
  1571.     if(6<rec.compression_method) rec.compression_method = 7;
  1572.     
  1573.     day        =      rec.last_mod_file_date & 0x1F;    
  1574.     month    =     (rec.last_mod_file_date >> 5) & 0x0F;
  1575.     year    =    ((rec.last_mod_file_date >> 9) & 0x7F) + 80;
  1576.     
  1577.     hour    =     (rec.last_mod_file_time >>11) & 0x1F;
  1578.     minute    =     (rec.last_mod_file_time >> 5) & 0x3F;
  1579.     second    =  2*(rec.last_mod_file_time & 0x1F);
  1580.  
  1581.     sprintf(tstring,"%-12s%s%10ld %10ld%4d-%3s-%2d  %02d:%02d:%02d  %08lX  %3s\015",
  1582.             filename,
  1583.             method[rec.compression_method],
  1584.             rec.compressed_size,
  1585.             rec.uncompressed_size,
  1586.             day,
  1587.             mo[month-1],
  1588.             year,
  1589.             hour,
  1590.             minute,
  1591.             second,
  1592.             rec.crc32,
  1593.             ny[rec.internal_file_attributes]);
  1594.             
  1595.     DisplayString(CtoPstr(tstring));
  1596.     offset    =    1L + rec.relative_offset_local_header;
  1597.     if (1==rec.internal_file_attributes) offset = -offset;
  1598.     return(offset);
  1599. }
  1600.  
  1601. /* ------------------------------------------------------------------------- */
  1602. int process_end_central_dir()
  1603. {
  1604.     end_central_dir_record rec;
  1605.     Rect    drect;
  1606.  
  1607.     memcpy(&rec,inbuf+incnt+1,sizeof(rec));
  1608.     incnt    =    incnt + 1 + sizeof(rec);
  1609.     
  1610.     swap_bytes(&rec.total_entries_central_dir);
  1611.     swap_lbytes(&rec.offset_start_central_directory);
  1612.     swap_bytes(&rec.zipfile_comment_length);
  1613.         
  1614.     wlistflag    =    true;
  1615.     wlist    =    GetNewDWindow(101,-1L);
  1616.     SetWTitle(wlist,&SFzipfd.fName);
  1617.     SetDWindowStyle(wlist,150,9,1,0);
  1618.     DisplayText(inbuf+incnt,(long) rec.zipfile_comment_length);
  1619.     
  1620.     if(fpos < rec.offset_start_central_directory)
  1621.     {
  1622.         dirflag    =    true;
  1623.         incnt    =    rec.offset_start_central_directory - fpos;
  1624.     }
  1625.     else
  1626.     {
  1627.         dirflag    =    false;
  1628.         lseek(zipfd,rec.offset_start_central_directory,0);
  1629.     }
  1630.     
  1631.     return(rec.total_entries_central_dir);
  1632. }
  1633.  
  1634. /* ------------------------------------------------------------------------- */
  1635. /*long labs(x)
  1636. long x;
  1637. {
  1638.     long y;
  1639.     y    =    x;
  1640.     if(0L>y)    y    =    -y;
  1641.     return(y);
  1642. }*/
  1643.  
  1644. /* ------------------------------------------------------------------------- */
  1645. void process_headers()
  1646. {
  1647.     longint sig;
  1648.     
  1649.     Boolean    abortflag=false;
  1650.  
  1651.     if(finishedflag) 
  1652.     {
  1653.         SysBeep(1);
  1654.         strcpy(tstring,"\015ZIP file extraction completed for this file!");
  1655.         ParamText(CtoPstr(tstring),"\p","\p","\p");
  1656.         HiliteMenu(nil);
  1657.         (void) StopAlert(101,nil);
  1658.         return;
  1659.     }
  1660.  
  1661.     c    =    GetCursor(watchCursor);
  1662.     SetCursor(*c);
  1663.     
  1664.     for (dindex=0;dindex<direntries;dindex++)
  1665.         {
  1666.             lseek(zipfd,labs(zipoffset[dindex])-1,0);
  1667.             
  1668.             read(zipfd, tstring, sizeof(sig));
  1669.             memcpy(&sig,tstring,sizeof(sig));
  1670.             
  1671.             if (sig != LOCAL_FILE_HEADER_SIGNATURE)
  1672.                 {
  1673.                     DisplayString("\pBad ZIP file local header signature--file skipped\015");
  1674.                 }
  1675.                 
  1676.                 
  1677.             else process_local_file_header();
  1678.             if(abortflag = check_abort())
  1679.             {
  1680.                 DisplayString("\p\r           * PROCESSING ABORTED *\r");
  1681.                 ParamText("\p\rProcessing aborted!","\p","\p","\p");
  1682.                 break;
  1683.             }
  1684.         }
  1685.     if(!abortflag) ParamText("\p\rZIP file extraction completed!","\p","\p","\p");
  1686.     InitCursor();
  1687.     close(zipfd);
  1688.     finishedflag    =    true;
  1689.     Delay(20L,sig);
  1690.     SysBeep(1);
  1691.     Delay(5L,sig);
  1692.     SysBeep(1);
  1693.     HiliteMenu(nil);
  1694.     (void) NoteAlert (101,nil);
  1695. }
  1696.      
  1697. /* ------------------------------------------------------------------------- */    
  1698. AllocateBuffers()
  1699. {
  1700.     int buffer_fail = 0;
  1701.  
  1702.     extern int *Prefix_of;
  1703.     extern byte *Suffix_of;
  1704.     extern byte *Stack;
  1705.     
  1706.     int i;
  1707.     
  1708.     Prefix_of = calloc(hsize+1,2);
  1709.     Suffix_of = calloc(hsize+1,1);
  1710.     Stack     = calloc(hsize+1,1);
  1711.  
  1712. /* allocate i/o buffers */
  1713.     inbuf         =    (char *) (malloc(INBUFSIZ));
  1714.     outbuf        =    (char *) (malloc(OUTBUFSIZ));
  1715.     in_size        =    INBUFSIZ;
  1716.     out_size    =    OUTBUFSIZ;
  1717.     
  1718.     if ((inbuf == NULL) || (outbuf == NULL)) 
  1719.     {
  1720.         ParamText("\pInsufficient memory to allocate buffers!","\p","\p","\p");
  1721.         (void) StopAlert (101,nil);
  1722.         SkelWhoa();
  1723.     }
  1724. }
  1725.  
  1726. /* ------------------------------------------------------------------------- */
  1727. aboutUnZip()
  1728. {
  1729.     (void) Alert(100,nil);
  1730. }
  1731.  
  1732. /* ------------------------------------------------------------------------- */
  1733. setLFflag()
  1734. {
  1735.     if (!stripLFflag) 
  1736.     {
  1737.         stripLFflag    =    true;
  1738.         CheckItem(mOptions,3,true);
  1739.         mstrip    =    NewMenu(5,"\p*Strip LF on*");
  1740.         SkelMenu(mstrip,nil,nil);
  1741.     }
  1742.     else
  1743.     {
  1744.         stripLFflag    =    false;
  1745.         CheckItem(mOptions,3,false);
  1746.         mstrip    =    NewMenu(5,"\p");
  1747.         SkelMenu(mstrip,nil,nil);
  1748.     }
  1749. }
  1750.  
  1751. /* ------------------------------------------------------------------------- */
  1752. setTEXTfilterflag()
  1753. {
  1754.     if (!TEXTfilterflag) 
  1755.     {
  1756.         TEXTfilterflag    =    true;
  1757.         CheckItem(mOptions,4,true);
  1758.         mfilter    =    NewMenu(4,"\p*.GIF & TEXT filter*");
  1759.         SkelMenu(mfilter,nil,nil);
  1760.     }
  1761.     else
  1762.     {
  1763.         TEXTfilterflag    =    false;
  1764.         CheckItem(mOptions,4,false);
  1765.         mfilter    =    NewMenu(4,"\p");
  1766.         SkelMenu(mfilter,nil,nil);
  1767.     }
  1768. }
  1769.  
  1770. /* ------------------------------------------------------------------------- */
  1771. setchoosefileflag()
  1772. {
  1773.     if (!choosefileflag) 
  1774.     {
  1775.         choosefileflag    =    true;
  1776.         CheckItem(mOptions,5,true);
  1777.     }
  1778.     else
  1779.     {
  1780.         choosefileflag    =    false;
  1781.         CheckItem(mOptions,5,false);
  1782.     }
  1783. }
  1784.  
  1785. /* ------------------------------------------------------------------------- */
  1786. openfile()
  1787. {
  1788.     extern int direntries;
  1789.     extern long fpos;
  1790.     long    sig;
  1791.     long    flength;
  1792.     long    temp;
  1793.     int        tbufsize;
  1794.     boolean    foundecdflag;
  1795.     
  1796.     DisableItem(mOptions,1);
  1797.     
  1798.     if(wlistflag)
  1799.     {
  1800.         if (!finishedflag) close(zipfd);
  1801.         SkelRmveWind(wlist);
  1802.         wlistflag        =    false;
  1803.     }
  1804.     finishedflag    =    false;
  1805.     
  1806.     SFGetFile(bloc,"\p",nil,-1,nil,nil,&SFzipfd);
  1807.     
  1808.     if(!SFzipfd.good) return;
  1809.     else SetVol("\p",SFzipfd.vRefNum);
  1810.     
  1811.     c    =    GetCursor(watchCursor);
  1812.     SetCursor(*c);
  1813.     memcpy(tstring,&SFzipfd.fName,64);
  1814.     zipfd        =    open(PtoCstr(tstring), O_RDONLY | O_BINARY);
  1815.     flength        =    lseek(zipfd,0L,2);
  1816.     fpos        =    flength - 8192;
  1817.     tbufsize    =    8192;
  1818.     if (0 > fpos)
  1819.     {
  1820.         fpos        =    0;
  1821.         tbufsize    =    flength;
  1822.     }
  1823.  
  1824.     lseek(zipfd,-(long) tbufsize,2);
  1825.     read(zipfd,inbuf,tbufsize);
  1826.     foundecdflag    =    false;
  1827.     
  1828.     for (incnt=tbufsize-18; incnt>4; incnt--)
  1829.     {
  1830.         if (('\006'== *(inbuf + (long)  incnt    )) &&
  1831.             ('\005'== *(inbuf + (long) (incnt-1) )) &&
  1832.             (   'K'== *(inbuf + (long) (incnt-2) )) &&
  1833.             (   'P'== *(inbuf + (long) (incnt-3) )))
  1834.         {
  1835.             foundecdflag    =    true;
  1836.             break;
  1837.         }
  1838.     }
  1839.     
  1840.     if (!foundecdflag)
  1841.     {
  1842.         /*    not a ZIP file alert    */
  1843.         memcpy(tstring,&SFzipfd.fName,64);
  1844.         PtoCstr(tstring);
  1845.         strcat(tstring,"\015\015Not a ZIP file!");
  1846.         ParamText(CtoPstr(tstring),"\p","\p","\p");
  1847.         InitCursor();
  1848.         SysBeep(1);
  1849.         HiliteMenu(nil);
  1850.         (void) StopAlert (101,nil);
  1851.         close(zipfd);
  1852.         return;
  1853.     }
  1854.         
  1855.     direntries    =    process_end_central_dir();
  1856.     
  1857.     DisplayString("\p\015\015File Name        Method  Size Now  Full Size     Date      Time       CRC   Text\015");
  1858.     DisplayString("\p---------      --------  --------  ---------  ---------  --------  -------- ----\015");
  1859.     
  1860.     for (dindex=0;dindex<direntries;dindex++)
  1861.     {
  1862.         if (dirflag)
  1863.         {
  1864.             memcpy(&sig,inbuf+incnt,sizeof(sig));
  1865.             incnt    =    incnt + sizeof(sig);
  1866.         }
  1867.         else
  1868.         {
  1869.             read(zipfd,tstring,sizeof(sig));
  1870.             memcpy(&sig,tstring,sizeof(sig));
  1871.         }
  1872.         
  1873.         if (sig == CENTRAL_FILE_HEADER_SIGNATURE) zipoffset[dindex]=process_central_file_header();
  1874.             
  1875.     }
  1876.     DisplayLn();
  1877.     InitCursor();
  1878.     EnableItem(mOptions,1);
  1879.     SysBeep(6);
  1880.     SetDWindowPos(wlist,0);
  1881.     ShowWindow(wlist);
  1882. }
  1883.  
  1884. /* ------------------------------------------------------------------------- */
  1885. DoFileMenu(item)
  1886. int item;
  1887. {
  1888.     switch(item)
  1889.     {
  1890.         case 1:    openfile();    break;
  1891.         case 2:    {
  1892.                     free(Prefix_of);
  1893.                     free(Suffix_of);
  1894.                     free(Stack);
  1895.                     free(inbuf);
  1896.                     free(outbuf);
  1897.                     SkelWhoa();
  1898.                     break;
  1899.                 }
  1900.     }
  1901. }
  1902.  
  1903. /* ------------------------------------------------------------------------- */
  1904. DoOptionsMenu(item)
  1905. int item;
  1906. {
  1907.     switch(item)
  1908.     {
  1909.         case 1:    process_headers(); break;
  1910.         case 2: break;
  1911.         case 3:    setLFflag(); break;
  1912.         case 4: setTEXTfilterflag();break;
  1913.         case 5: setchoosefileflag(); break;
  1914.     }
  1915. }
  1916.     
  1917. /* ------------------------------------------------------------------------- */
  1918. void main()
  1919. {
  1920.     SkelInit(6,nil);
  1921.     SkelApple("\pAbout UnZip 1.02c╔",aboutUnZip);
  1922.  
  1923.     mFile        =    GetMenu(101);
  1924.     (void) SkelMenu(mFile,DoFileMenu,nil,false);
  1925.     mOptions    =    GetMenu(102);
  1926.     (void) SkelMenu(mOptions,DoOptionsMenu,nil,true);
  1927.     
  1928.     AllocateBuffers();
  1929.     SkelMain();
  1930.     SkelClobber();
  1931. }
  1932.